package search.impl;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class InterpolateArray<K, V> implements search.text.SymbolTable {
    private static final int SIZE = 100;
    private Entry<K, V>[] objects;
    private int n;

    public InterpolateArray() {
        objects = new EntryObject[SIZE];
        n = 0;
    }

    public int size() {
        return n;
    }

    public boolean isEmpty() {
        return n == 0;
    }

    public boolean containsKey(Object key) {
        int i = interSearch(key);
        return i != -1;
    }

    public Object get(Object key) throws Exception {
        int i = interSearch(key);
        if (i == -1) {
            throw new Exception("No se ha encontrado");
        } else {
            return objects[i];
        }
    }


    public void put(Object key, Object value) {
        int index = interSearch(key);
        if (isFull()) {
            duplicate();
        }
        if (index >= 0) {
            objects[index] = new EntryObject(key, value);
            return;
        }
        int i = n;
        while (i > 0 && (Math.abs(key.hashCode()) - Math.abs((objects[i - 1].getKey().hashCode()))) < 0) {
            objects[i] = objects[i - 1];
            i--;
        }
        objects[i] = new EntryObject(key, value);
        n++;
    }

    private int interSearch(Object key) {
        int lo = 0;
        int hi = n - 1;
        while (hi >= lo) {
            double k = Math.abs(key.hashCode());
            double k1 = Math.abs((objects[lo].getKey()).hashCode());
            double kn = Math.abs((objects[hi].getKey()).hashCode());

            if (k <= k1 || k >= kn) return -1;
            int m = (int) (((k - k1) / (kn - k1)) * (n));
            int cmp = Math.abs(key.hashCode()) - Math.abs((objects[m].getKey().hashCode()));
            if (cmp < 0) hi = m - 1;
            else if (cmp > 0) lo = m + 1;
            else if (cmp == 0) return m;
        }
        return -1;
    }

    private void duplicate() {
        Entry<K, V>[] newObjects = new EntryObject[n * 2];
        System.arraycopy(objects, 0, newObjects, 0, objects.length);
        n *= 2;
    }

    public void clear() {
        objects = new EntryObject[SIZE];
        n = 0;
    }

    public Set entrySet() {
        Set<Entry<K, V>> set = new HashSet<Entry<K, V>>();
        set.addAll(Arrays.asList(objects));
        return set;
    }

    public boolean isFull() {
        return n == objects.length;
    }
}

